﻿using System;
using System.Web.UI;

using Carbon.Web.Forms.Extensions;

namespace Carbon.Web.Forms.Controls
{
    [ParseChildren(true)]
    [PersistChildren(false)]
    public class IfElsePanel : ViewControlBase, INamingContainer, IDataProxy
    {
		#region Classes (1)
		private class IfElsePanelContainer : Control, INamingContainer
        {
        }
		#endregion

		#region Fields (7)
		private bool m_DataContext_calculated = false;
		private bool m_NullValue = default(bool);

		private Object m_DataContext = default(Object);

		private String m_ConditionDataPath = default(String);
		private String m_DataContextPath = default(String);

		private ITemplate m_ElseTemplate = default(ITemplate);
		private ITemplate m_IfTemplate = default(ITemplate);
		#endregion

		#region Events (1)
		public event EventHandler<ConditionEventArgs> Condition;
		#endregion

		#region Properties (6)
		/// <summary>
        /// If the value on condition data path true then IfTemplate is shown, else ElseTemplate is shown.
        /// If the value on condition data path is null, then if NullValue property is false, value ElseTemplate is shown.
        /// </summary>
        public String ConditionDataPath
        {
            get
            {
                return m_ConditionDataPath;
            }
            set
            {
                m_ConditionDataPath = value;
            }
        }
		public Object DataContext
        {
            get
            {
                if (!m_DataContext_calculated)
                {
                    m_DataContext = this.GetViewModelContext();
                    if (m_DataContext == null)
                        throw new InvalidOperationException("Data context is null.");

                    if (!string.IsNullOrEmpty(DataContextPath))
                        m_DataContext = new Binder(m_DataContext, DataContextPath, true).Value;

                    m_DataContext_calculated = true;
                }

                return m_DataContext;
            }
        }
		/// <summary>
        /// Sets the data context to some other value according to this data path and existing data context.
        /// </summary>
        public String DataContextPath
        {
            get
            {
                return m_DataContextPath;
            }
            set
            {
                m_DataContextPath = value;
            }
        }
        
        [PersistenceMode(PersistenceMode.InnerProperty)]
		public ITemplate ElseTemplate
        {
            get
            {
                return m_ElseTemplate;
            }
            set
            {
                m_ElseTemplate = value;
            }
        }

        [PersistenceMode(PersistenceMode.InnerProperty)]
		public ITemplate IfTemplate
        {
            get
            {
                return m_IfTemplate;
            }
            set
            {
                m_IfTemplate = value;
            }
        }
		public bool NullValue
        {
            get
            {
                return m_NullValue;
            }
            set
            {
                m_NullValue = value;
            }
        }
		#endregion

		#region Methods (3)

		protected virtual void OnCondition(ConditionEventArgs args)
        {
            if (Condition != null)
            {
                Condition(this, args);
            }
            else
            {
                Object dataContext = DataContext;

                if (string.IsNullOrEmpty(ConditionDataPath)) throw new ArgumentOutOfRangeException("ConditionDataPath");

                object condition = new Binder(dataContext, ConditionDataPath, true).Value;

                if (condition == null)
                {
                    args.Result = NullValue;
                }
                else
                {
                    args.Result = ConvertInvariant.ToBoolean(condition);
                }
            }
        }

        protected override IEditor CreateEditor()
        {
            return null;
        }
        
        private bool? m_LastConditionValue = default(bool?);
        public bool? LastConditionValue
        {
            get
            {
                return m_LastConditionValue;
            }
            set
            {
                m_LastConditionValue = value;
            }
        }

        private bool m_ViewControlsCreated = default(bool);
        protected bool ViewControlsCreated
        {
            get
            {
                return m_ViewControlsCreated;
            }
            set
            {
                m_ViewControlsCreated = value;
            }
        } 

		public override void OnUpdateControl(object sender, UpdateControlEventArgs args)
        {
            m_DataContext_calculated = false;

            ConditionEventArgs args2 = new ConditionEventArgs();

            OnCondition(args2);

            if (ViewControlsCreated && (args2.Result == LastConditionValue))
                return;

            IfElsePanelContainer ifContainer = new IfElsePanelContainer();
            IfElsePanelContainer elseContainer = new IfElsePanelContainer();

            this.Controls.Clear();
            this.Controls.Add(ifContainer);
            this.Controls.Add(elseContainer);

            if (args2.Result)
            {
                if (IfTemplate != null)
                    IfTemplate.InstantiateIn(ifContainer);
            }
            else
            {
                if (ElseTemplate != null)
                    ElseTemplate.InstantiateIn(elseContainer);
            }

            LastConditionValue = args2.Result;
            ViewControlsCreated = true;
        }

		public override void OnUpdateModel(object sender, UpdateModelEventArgs args)
        {
            m_DataContext_calculated = false;
        }

		#endregion
    }
}
